/*
 * Copyright (C) 2004-2005, Universidade Federal de Campina Grande. All rights reserved.
 */
package org.epanetgrid.otimizacao.ag;

import org.jheuristics.Individual;
import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.operators.Probability;
import org.jheuristics.ga.operators.Reproductor;
import org.jheuristics.ga.operators.reproductors.GensListOnePointXOver;
import org.jheuristics.ga.operators.reproductors.funcionalidades.IListXOver;

/**
 * (ver especifica��o para mais detalhes)
 * @author Vin�cius Ferraz Campos, vinicius.ferraz@gmail.com
 *
 */
public class CrossverDirecionadoEsther extends GensListOnePointXOver {

	/**
	 * 
	 * @param probability Probabilidade do cruzamento ocorrer
	 * @param maxTryOuts N�mero m�ximo de tentativas
	 * @param listXOver Classe respons�vel por efetuar o cruzamento (editor de funcionalidades)
	 */
	public CrossverDirecionadoEsther(Probability probability, int maxTryOuts, IListXOver listXOver) {
		super(probability, maxTryOuts, listXOver);
	}

	/**
	 * 
	 * @param decoretedReproductor Reprodutor
	 * @param probability Probabilidade do cruzamento ocorrer
	 * @param tryOuts N�mero m�ximo de tentativas
	 * @param listXOver Classe respons�vel por efetuar o cruzamento (editor de funcionalidades)
	 */
	public CrossverDirecionadoEsther(Reproductor decoretedReproductor, Probability probability, int tryOuts, IListXOver listXOver) {
		super(decoretedReproductor, probability, tryOuts, listXOver);
	}

	/* (non-Javadoc)
	 * @see org.jheuristics.ga.operators.Reproductor#reproduce(org.jheuristics.Individual[], org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	public Individual[] reproduce(Individual[] parents, GAStatus status, GAConfig config) {
    	if (null == parents) {
            throw new NullPointerException();
    	}
    	if (2 > parents.length) {
    		throw new IllegalArgumentException();
    	}
    	for (int i = 0; i < 2; i++) {
    		if (null == parents[i]) {
                throw new NullPointerException();
    		}
    	}
        if (null == config) {
            throw new NullPointerException();
        }
        if (null != getDecoratedReproductor()) {
        	try{
        	int erroParent1 = ((SimpleFitness) parents[0].getFitness()).getIntervaloDeErro();
        	int erroParent2 = ((SimpleFitness) parents[1].getFitness()).getIntervaloDeErro();
        	if ((3 > erroParent1 && erroParent1 != -1) || (3 > erroParent2 && erroParent2 != -1) || (erroParent1 == erroParent2 && erroParent1 != -1)) {
        		return decorate(parents, status, config);
        	}
        	}catch(Exception e) {
        		e.printStackTrace();
        		return null;
        		}
        }
    	Individual[] result = null;
    	StringBuffer buffer = new StringBuffer();
    	buffer.append("Verificando probabilidade de cruzamento Direcionado:");
    	buffer.append("\n");
    	if (getProbability().check(status, config)) {
    		buffer.append("Cruzamento direcionado ser� efetuado");
    		buffer.append("\n");
    		logger.debug(buffer);
            return xover(parents, status, config);
    	}else {
    		buffer.append("Cruzamento direcionado N�o ser� efetuado");
    		buffer.append("\n");
    		logger.debug(buffer);
    	}
    	
    	if (null == result) {
    		result = new Individual[] {parents[0], parents[1]};
    	}
		return result;
	}

	/* (non-Javadoc)
	 * @see org.jheuristics.ga.operators.reproductors.GensListOnePointXOver#chooseXOverPoints(org.jheuristics.Individual, org.jheuristics.Individual, org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	protected int[] chooseXOverPoints(Individual parent1, Individual parent2, GAStatus status, GAConfig config) {
    	int erroParent1 = ((SimpleFitness) parent1.getFitness()).getIntervaloDeErro();
    	int erroParent2 = ((SimpleFitness) parent2.getFitness()).getIntervaloDeErro();
    	if (erroParent1 == erroParent2 && erroParent1 == -1) {
    		return super.chooseXOverPoints(parent1, parent2, status, config);
    	} else {
    		int min = Math.min(erroParent1, erroParent2);
    		if (min == -1) {
    			return new int[] {Math.max(erroParent1, erroParent2) - 3};
    		}
    		return new int[] {min - 3};
    	}
	}

}
